//Game Code

#include <iostream>
#include <cmath>
#include <vector>
#include <fstream>
#include <string>
#include <algorithm>
#include "game.h"

using namespace std;

#define GRAV 0
#define RED 1
#define GREEN 2
#define GRAV_CONST 0.05
#define BOOST_CONST 3
#define TIME_STEP 0.03
#define LIFE_LOST_ON_COLLISION 0.2
#define LIFE_GAIN_ON_COLLISION 0.04

#define MASS(x) (4.0/3.0 * 3.14159 * x.radius * x.radius * x.radius)
#define DISTANCE(k, q) (sqrt(abs(k.x - q.x) * abs(k.x - q.x) + abs(k.y - q.y) * abs(k.y - q.y)))
#define FORCE(k, q) (GRAV_CONST * MASS(k) * MASS(q)) / (DISTANCE(k, q) * DISTANCE(k, q))
#define ANGLE(k, q) (atan2((k.y - q.y), (k.x - q.x)))
#define XFORCE(k, q) (FORCE(k, q) * cos(ANGLE(k, q)))
#define YFORCE(k, q) (FORCE(k, q) * sin(ANGLE(k, q)))

ball theBall;
vector<target> targets;
player playerOne;
player playerTwo;
unsigned int DropInfoCalls = 0;
int objectCount = 0;
vector<DropObject> Drops;

 bool operator< (const DropObject& Object1, const DropObject& Object2) {       
	 return (Object1.spawnTime < Object2.spawnTime);
 }


/* for(int = 1; i < 300000; i++)
 {
	 if(rand() < 0.07)
	 {
		 out << i << " " << rand_x << " " << rand_rad << " " << rand_type << endl;
	 }
 }*/
DropObject DropInfo() {
	DropInfoCalls++;

	//0 is gravity
	//1 is red
	//2 is green

	if(DropInfoCalls == 1) { // first time, get all object info
		ifstream infile("D:\\gravity GID\\Lesson05\\dropinfo.txt");
		DropObject newDropObject = { 0, 0, 0, 0 };
		
		Drops.push_back(newDropObject);
		while(infile >> newDropObject.spawnTime >> newDropObject.spawnX >> newDropObject.spawnRadius >> newDropObject.spawnType) {
			Drops.push_back(newDropObject);
			//cout << Drops.size();
		}
		//sort(Drops.begin(), Drops.end());
	}
	if(Drops.size() - 1 == objectCount)
		return Drops[0];
	if(Drops[objectCount + 1].spawnTime == DropInfoCalls) { // time to spawn object
		objectCount++;
		return Drops[objectCount];
	}

	return Drops[0];		
}	

player getPlayer(int playerNum)
{
	player x;
	x.isBoost = true;
	x.isOn = false;
	x.x = 0.5;
	x.y = 0.5;
	x.radius = 0.1;
	return x;
}
/*
DropObject DropInfo()
{
	DropObject o;
	o.spawnRadius = 0.1;
	o.spawnTime = 0;
	o.spawnType = RED;
	o.spawnX = 0.4;
	return o;
}*/

vector<target> targetLocations()
{
	return targets;
}

ball ballLocation()
{
	return theBall;
}

player playerPower(int playerNum)
{
	if(playerNum == 0)
		return playerOne;
	else
		return playerTwo;
}

void calculate_iteration()
{
	if(theBall.life == 0)
		return;
	float x_force, y_force;
	int boost = 1;
	player playerOne = getPlayer(0);
	if((playerOne.x - theBall.x < 0.05) && (playerOne.x - theBall.x >= 0))
	{
		theBall.x = playerOne.x - 0.05;
	}
	if((playerOne.x - theBall.x > -0.05) && (playerOne.x - theBall.x <= 0))
	{
		theBall.x = playerOne.x + 0.05;
	}
	if((playerOne.y - theBall.y < 0.05) && (playerOne.y - theBall.y >= 0))
	{
		theBall.y = playerOne.y - 0.05;
	}
	if((playerOne.y - theBall.y > -0.05) && (playerOne.y - theBall.y <= 0))
	{
		theBall.y = playerOne.y + 0.05;
	}

	player playerTwo = getPlayer(1);
	if((playerTwo.x - theBall.x < 0.05) && (playerTwo.x - theBall.x >= 0))
	{
		theBall.x = playerTwo.x - 0.05;
	}
	if((playerTwo.x - theBall.x > -0.05) && (playerTwo.x - theBall.x <= 0))
	{
		theBall.x = playerTwo.x + 0.05;
	}
	if((playerTwo.y - theBall.y < 0.05) && (playerTwo.y - theBall.y >= 0))
	{
		theBall.y = playerTwo.y - 0.05;
	}
	if((playerTwo.y - theBall.y > -0.05) && (playerTwo.y - theBall.y <= 0))
	{
		theBall.y = playerTwo.y + 0.05;
	}

	if(playerOne.isBoost || !playerOne.isOn)
	{
		playerOne.power -= 0.001;
		if(playerOne.power <= 0)
		{
			playerOne.power = 0;
			playerOne.isBoost = false;
			playerOne.isOn = true;
		}
	}
	if(playerTwo.isBoost || !playerTwo.isOn)
	{
		playerTwo.power -= 0.001;
		if(playerTwo.power <= 0)
		{
			playerTwo.power = 0;
			playerTwo.isBoost = false;
			playerTwo.isOn = true;
		}
	}

	x_force = 0; y_force = 0;
	if(playerOne.isBoost)
	{
		boost = BOOST_CONST;
	}
	else
	{
		boost = 1;
	}
	if(playerOne.isOn)
	{
		x_force += boost * XFORCE(playerOne, theBall);
		y_force += boost * YFORCE(playerOne, theBall);
	}
	if(playerTwo.isBoost)
	{
		boost = BOOST_CONST;
	}
	else
	{
		boost = 1;
	}
	if(playerTwo.isOn)
	{
		x_force += boost * XFORCE(playerTwo, theBall);
		y_force += boost * YFORCE(playerTwo, theBall);
	}
	for(int i = 0; i < targets.size(); i++)
	{
		if(targets[i].type == GRAV && !targets[i].beenHit)
		{
			x_force += boost * XFORCE(targets[i], theBall);
			y_force += boost * YFORCE(targets[i], theBall);
		}
	}
	theBall.x_v += x_force / MASS(theBall);
	theBall.y_v += y_force / MASS(theBall);
	//velocity changed, now update everythings position!
	float newBallX = theBall.x + theBall.x_v * TIME_STEP;
	float newBallY = theBall.y + theBall.y_v * TIME_STEP;
	if(newBallX - theBall.radius < 0)
	{
		newBallX = -(newBallX - theBall.radius) + theBall.radius;
		theBall.x_v = -theBall.x_v;
	}
	if(newBallY - theBall.radius < 0)
	{
		newBallY = -(newBallY - theBall.radius) + theBall.radius;
		theBall.y_v = -theBall.y_v;
	}
	if(newBallX + theBall.radius > 1)
	{
		newBallX = 2 - (newBallX + theBall.radius) - theBall.radius;
		theBall.x_v = -theBall.x_v;
	}
	if(newBallY + theBall.radius > 1)
	{
		newBallY = 2 - (newBallY + theBall.radius) - theBall.radius;
		theBall.y_v = -theBall.y_v;
	}
	float oldBallX = theBall.x;
	float oldBallY = theBall.y;
	theBall.x = newBallX;
	theBall.y = newBallY;
	for(int i = 0 ; i < targets.size(); i++)
	{
		targets[i].y += TIME_STEP * 2;
		cout << targets[i].y << ",";
		if(DISTANCE(targets[i], theBall) < (targets[i].radius + theBall.radius) && !targets[i].beenHit)
		{
			if(targets[i].type == GRAV)
			{
				targets[i].beenHit = true;
			}
			else if(targets[i].type == RED)
			{
				//destroy target, decrement life
				theBall.life -= LIFE_LOST_ON_COLLISION;
				targets[i].beenHit = true;
			}
			else
			{
				//destroy target, increment life
				theBall.life += LIFE_GAIN_ON_COLLISION;
				playerOne.power += 0.05;
				targets[i].beenHit = true;
			}
		}
	}
	cout << endl;
	if(theBall.life < 0)
		theBall.life = 0;
	if(theBall.life > 1)
		theBall.life = 1;
	DropObject toAdd = DropInfo();
	if(toAdd.spawnTime != 0)
	{
		target addtarget;
		addtarget.beenHit = false;
		addtarget.radius = toAdd.spawnRadius;
		addtarget.x = toAdd.spawnX;
		addtarget.y = -toAdd.spawnRadius;
		addtarget.type = toAdd.spawnType;
		targets.push_back(addtarget);
	}
}

void initGame()
{
	theBall.life = 1;
	theBall.radius = 0.05;
	theBall.type = 3;
	theBall.x = 0.5;
	theBall.y = 0.5;
	theBall.x_v = 0;
	theBall.y_v = 0;

	targets.clear();

}

int main()
{
	initGame();
	for(int i = 0; i < 100; i++)
	{
		calculate_iteration();
		cout << theBall.x << "," << theBall.y << endl;
	}
	return 0;
}